#pragma once

#include <fcntl.h>
#include <unistd.h>

#include <atomic>
#include <mutex>
#include <stdexcept>
#include <thread>
#include <vector>

#include <bthread/bthread.h>
#include <bthread/condition_variable.h>
#include <bthread/mutex.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <liburing.h>

#include "base/common.h"
#include "util/fileaio/aio_option.h"
#include "util/status.h"

namespace hawking {
namespace indexlib {

struct DiskFileArgs {
    struct iovec iov;

    bthread::ConditionVariable cv;
    std::atomic<int32_t> done_flag;
    Status status = Status::OK;
    int32_t size = 0;

    DiskFileArgs(void* buf, size_t len) : done_flag(0) {
        iov.iov_base = buf;
        iov.iov_len = len;
    }
};

class DiskFileReadProcesser {
public:
    DiskFileReadProcesser() {
        concurrency_.store(0);
        start_.store(false, std::memory_order_relaxed);
        read_request_count_.store(0, std::memory_order_relaxed);
        read_response_count_.store(0, std::memory_order_relaxed);
    }
    ~DiskFileReadProcesser();

    bool Init(const AioOption& opt, const char* file_path, bool need_stat_thread);
    bool Read(off_t offset, DiskFileArgs* args);
    ReturnValue<int32_t> Read(uint8_t* buffer, size_t length, off_t offset);
    void Wait(DiskFileArgs& arg);
    int32_t Fd() const {
        return fd_;
    }

private:
    struct io_uring ring_;
    int32_t fd_ = -1;
    std::string filename_ = "";

    std::atomic<int32_t> concurrency_;
    static constexpr int32_t max_concurrency_ = 1;

    std::atomic<bool> start_;
    std::thread io_uring_dispose_thread_;
    std::thread stat_thread_;

    // for stat
    std::atomic<uint64_t> read_request_count_;
    std::atomic<uint64_t> read_response_count_;

    //TODO(mander.liu) add sample read-cost
};

}
}
